package biopepa;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class NewSpecies {
	public String speciesName;
	public int speciesUpper;
	public int speciesLower;
	public int speciesInitial;
	public boolean isContinuous;
	public boolean hasComponent;
	private HashMap< String , ActionEnabled > actionsEnabledObjects;
	private HashMap< String , Displacement > displacementObjects;
	public HashMap< NewSpecies , ArrayList<ActionEnabled> > speciesCoop;
	public HashMap< NewCompositionalDef , ArrayList<ActionEnabled> > compositionalDefCoop;
	public HashMap<String , LocationAndInitial> locationsAccessible;
	
	public NewSpecies(String name){
		
		this.speciesName = name;
		this.speciesLower = 0;
		speciesInitial = -1;
		//this.speciesType = Type.discrete;
		isContinuous = false;
		actionsEnabledObjects = new HashMap< String , ActionEnabled > ();
		displacementObjects = new HashMap< String , Displacement>();
		this.compositionalDefCoop = new HashMap< NewCompositionalDef , ArrayList<ActionEnabled> >();
		this.speciesCoop = new HashMap< NewSpecies , ArrayList<ActionEnabled> > () ;
		this.locationsAccessible = new HashMap<String , LocationAndInitial>();
		
	}
	
	public ActionEnabled getActionEnabled(String name){
		ActionEnabled action = actionsEnabledObjects.get(name);
		return action;
	}
	
	public HashMap< String , ActionEnabled > getActionsEnabledObjects(){
		HashMap< String , ActionEnabled > list = actionsEnabledObjects;
		return list;
	}
	
	public HashMap< String , Displacement > getDisplacementObjects(){
		HashMap< String , Displacement > list = displacementObjects;
		return list;
	}
	
	public void setUpper(SpeciesAndLocations speciesAndLocations , String upper){
		int size =speciesAndLocations.locations.size();
		if(size != 0){
		int i;
		for(i=0; i<size; i++){
			speciesAndLocations.locations.get(i).upper = Integer.parseInt(upper);
		}
		}
		else{
			speciesUpper = Integer.parseInt(upper);
		}
	}

	public void setSpeciesLower(String lower){
		speciesLower =  Integer.parseInt(lower);
	}
	
	public void setSpeciesInitial(String num){
		speciesInitial = Integer.parseInt(num);
	}
	
	public void setSpeciesType(String newType){
		if(newType == "continuous"){
		isContinuous = true;
		}
	}
	
	public void addActionEnabled(String name, String stoich, String op){
		ActionEnabled action;
		action = new ActionEnabled(name , stoich , op);
	    actionsEnabledObjects.put(name , action);
	}
	
	public void addActionEnabled(ActionEnabled action){
	    actionsEnabledObjects.put(action.actionEnabledNameWithLoc , action);
	}
	
	public void addActionsEnabledCoop(NewSpecies species , ArrayList<ActionEnabled> actionList){
	    speciesCoop.put(species , actionList);
	}
	
	public void addDisplacement(String newDisplacementName , String newStoich, String newOp, LocationAndInitial newSurce, LocationAndInitial newTarget){
		Displacement displacement = new Displacement( newDisplacementName, newStoich,  newOp, newSurce, newTarget);
	    displacementObjects.put( newDisplacementName , displacement);
	}
	
	public void addLocationsAccessible(LocationAndInitial locationAndInitial){
	    locationsAccessible.put(locationAndInitial.location.locationName , locationAndInitial);
	}
	
	public void addLocationsAccessible(NewLocation newLocation){
		LocationAndInitial newLocationAndInitial = new LocationAndInitial(newLocation);
	    locationsAccessible.put(newLocationAndInitial.location.locationName , newLocationAndInitial);
	}
	
	public void addLocationsAccessibleArray(ArrayList<LocationAndInitial> locations){
		int size = locations.size();
		int i;
		for(i=0; i<size; i++){
			addLocationsAccessible(locations.get(i));
		}
	}
	
	public void addInitialValues(ArrayList<LocationAndInitial> newLocations , String value){
		int newLocationsSize = newLocations.size();
		int i;
		if(newLocationsSize !=0){
			for(i=0; i<newLocationsSize; i++)
			{ 
				String loc = newLocations.get(i).location.locationName;
				if(locationsAccessible.get(loc).initial != 0){
					throw new BiopepaException("Error: multiple definition for initial value for the species '" + this.speciesName + "'.");
				}
				else{
					locationsAccessible.get(loc).initial = Integer.parseInt(value);	
				}
			}
		}
		else{
			speciesInitial = Integer.parseInt(value);	
		}
	}
	
	public String getSpeciesName(NewSpecies newName) {
		return newName.speciesName;
	}
	
	public boolean isActionEnabled(String name) {
        return actionsEnabledObjects.containsKey(name);
    }
	
		//Controllo1: Aggiunge l'azione nel caso in cui non sia presente
	
			public void actionsEnabledCheck1(String name){
				if(isActionEnabled(name) == true)
				{ }
				else
				{ addActionEnabled(name , null , null);
				}
			}
		

		public void actionEnabledCheck2(SpeciesAndAction speciesAndAction){
			
				 if(speciesAndAction.isDisplacement == false){
					 int i;
					 int locSize = speciesAndAction.locations.size();
					 if(locSize == 0){
						 ActionEnabled actionToAdd; 
						 actionToAdd = new ActionEnabled( speciesAndAction.actionName , speciesAndAction.stoich , speciesAndAction.op );
						 addActionEnabled(actionToAdd);
					 	}
					 else{	 
						 for(i=0; i<locSize; i++){
							 ActionEnabled actionToAdd; 
							 actionToAdd = new ActionEnabled( speciesAndAction.actionName, speciesAndAction.locations.get(i) , speciesAndAction.stoich , speciesAndAction.op );				 
							 addActionEnabled(actionToAdd);
							 addLocationsAccessibleArray(speciesAndAction.locations);
						 	}
					 	}
				 }
				 else if(speciesAndAction.isDisplacement == true){
					 addDisplacement(speciesAndAction.actionName, speciesAndAction.stoich, speciesAndAction.op , speciesAndAction.locations.get(0), speciesAndAction.locations.get(1) );
					 addLocationsAccessibleArray(speciesAndAction.locations);
				 }
		}
		
		//Controllo3: Controlla che tutte le azioni presenti nella comp modello siano definite
		
		public void actionEnabledCheck3(String name){
		      if(isActionEnabled(name) == true)
			  { }
			 else{ 
				 throw new BiopepaException("Action '" + name + "' in model component is undefined.");
			   }
		}
		
		//Controllo1: Controlla che nella model component le location siano accessibili per la species
		public void checkLocationAccessible(ArrayList<LocationAndInitial> locations){
			int locationsSize=locations.size();
			int i;
			for(i=0; i<locationsSize; i++){
				String loc = locations.get(i).location.locationName;
				if( locationsAccessible.containsKey(loc)){					
				}
				else{
					throw new BiopepaException("Error: location '" + loc + "' is not accessible for the species '" + this.speciesName + "'.");
				}
			}
		}




}
